
package cn.org.seventh.web.common;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.LastModified;

public abstract class CustomSingleActionController extends CustomAbstractController
                                                                          implements
                                                                          LastModified {

    /** Default command name used for binding command objects: "command" */
    public static final String DEFAULT_COMMAND_NAME = "command";

    /** List of Validators to apply to commands */
    private Validator[] validators;

    public Validator[] getValidators() {
        return validators;
    }

    public void setValidators(Validator[] validators) {
        this.validators = validators;
    }

    /**
     * Bind request parameters onto the given command bean
     * 
     * @param request
     *            request from which parameters will be bound
     * @param command
     *            command object, that must be a JavaBean
     * @throws Exception
     *             in case of invalid state or arguments
     */
    public void bind(HttpServletRequest request, Object command)
                                                                throws Exception {
        logger
            .debug("Binding request parameters onto MultiActionController command");
        ServletRequestDataBinder binder = createBinder(request, command);
        binder.bind(request);
        if (this.validators != null) {
            for (int i = 0; i < this.validators.length; i++) {
                if (this.validators[i].supports(command.getClass())) {
                    ValidationUtils.invokeValidator(this.validators[i],
                        command, binder.getBindingResult());
                }
            }
        }
        binder.closeNoCatch();
    }

    /**
     * Create a new binder instance for the given command and request.
     * <p>
     * Called by <code>bind</code>. Can be overridden to plug in custom ServletRequestDataBinder subclasses.
     * <p>
     * The default implementation creates a standard ServletRequestDataBinder, and invokes <code>initBinder</code>. Note that <code>initBinder</code> will not be invoked if you override this
     * method!
     * 
     * @param request
     *            current HTTP request
     * @param command
     *            the command to bind onto
     * @return the new binder instance
     * @throws Exception
     *             in case of invalid state or arguments
     * @see #bind
     * @see #initBinder
     */
    private ServletRequestDataBinder createBinder(HttpServletRequest request,
                                                  Object command)
                                                                 throws Exception {
        ServletRequestDataBinder binder =
            new ServletRequestDataBinder(command, getCommandName(command));
        initBinder(request, binder);
        return binder;
    }

    /**
     * Return the command name to use for the given command object.
     * <p>
     * Default is "command".
     * 
     * @param command
     *            the command object
     * @return the command name to use
     * @see #DEFAULT_COMMAND_NAME
     */
    protected String getCommandName(Object command) {
        return DEFAULT_COMMAND_NAME;
    }

    /**
     * Initialize the given binder instance, for example with custom editors. Called by <code>createBinder</code>.
     * <p>
     * This method allows you to register custom editors for certain fields of your command class. For instance, you will be able to transform Date objects into a String pattern and back, in order to
     * allow your JavaBeans to have Date properties and still be able to set and display them in an HTML interface.
     * <p>
     * The default implementation is empty.
     * <p>
     * Note: the command object is not directly passed to this method, but it's available via {@link org.springframework.validation.DataBinder#getTarget()}
     * 
     * @param request
     *            current HTTP request
     * @param binder
     *            new binder instance
     * @throws Exception
     *             in case of invalid state or arguments
     * @see #createBinder
     * @see org.springframework.validation.DataBinder#registerCustomEditor
     * @see org.springframework.beans.propertyeditors.CustomDateEditor
     */
    protected void initBinder(HttpServletRequest request,
                              ServletRequestDataBinder binder) throws Exception {
    }

    @Override
    public abstract ModelAndView handleRequestInternal(HttpServletRequest request,
                                                 HttpServletResponse response)
                                                                              throws Exception ;

    public long getLastModified(HttpServletRequest request) {
        return 0;
    }
}
